﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using WooCoo.Data;

namespace WooCoo.ObjectModel
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public abstract partial class Entity : ManagedProperty.ManagedPropertyBase, IEntityOrList
    {
        public Entity()
        {
            this.ValidationRules.CheckRules();
        }

        /// <summary>
        /// 通过实体类型反射构造一个新的实体。
        /// 
        /// 此方法功能与构造函数一致，主要用于不能显式调用的场景下。
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        [DebuggerStepThrough]
        public static Entity New(Type entityType)
        {
            //经测试，Activator 创建对象也非常快，这是因为它的内部作了缓存处理。
            var newE = Activator.CreateInstance(entityType, true) as Entity;
            newE.MarkNew();
            return newE;
        }

        #region 数据操作
        [NonSerialized]
        private IRepository _repository;
        /// <summary>
        /// 数据仓库操作，如果对于服务模式，该方式在服务端被调用
        /// 默认的数据库配置名为“Default”
        /// </summary>
        /// <returns></returns>
        public virtual IRepository GetRepository()
        {
            if (this._repository == null)
            {
                this._repository = RepositoryFactoryHost.Factory.Create(this.GetType());
            }

            return this._repository;
        }

        #endregion

        #region Object ID Value

        /// <summary>
        /// 重写该方法以返回对象的唯一标识
        /// </summary>
        public virtual object GetIdValue()
        {
            return null;
        }        

        #endregion

        #region 父子对象处理
        [NonSerialized]
        private IEntityOrList _parent;
        /// <summary>
        /// 父对象
        /// </summary>
        public IEntityOrList Parent
        {
            get { return this._parent; }
        }
        /// <summary>
        /// 设置父对象指向
        /// </summary>
        /// <param name="parent"></param>
        void IEntityOrList.SetParent(IEntityOrList parent)
        {
            this._parent = parent;
            //this.MarkAsChild();
        }

        public void DeleteChild()
        {
            this.MarkDeleted();
        }
        #endregion

        #region PropertyChanged
        protected override void OnPropertyChanged(string propertyName)
        {
            base.OnPropertyChanged(propertyName);
            this.ValidationRules.Validate(propertyName);
            if (this._status == PersistenceStatus.Unchanged)
            {
                this._status = PersistenceStatus.Modified;
            }
        }
        #endregion

        #region Get&Set&Load Property

        public void GetLazyProperty<T>(ManagedProperty.PropertyInfo<T> property)
        {
            if (!(this.FieldDataManager.FieldExists(property)))
            {
                //var child = 
                LoadProperty(property, default(T));
            }
        }
        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <param name="property"></param>
        /// <param name="value"></param>
        public override void SetProperty(ManagedProperty.IPropertyInfo property, object value)
        {
            if (value is IEntityOrList)
                (value as IEntityOrList).SetParent(this);
            base.SetProperty(property, value);
        }
        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="property"></param>
        /// <param name="value"></param>
        public override void SetProperty<T>(ManagedProperty.PropertyInfo<T> property, T value)
        {
            if (value is IEntityOrList)
                (value as IEntityOrList).SetParent(this);
            base.SetProperty<T>(property, value);
        }
        /// <summary>
        /// 加载属性值，该方法不会触发属性变更事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="property"></param>
        /// <param name="value"></param>
        public override void LoadProperty<T>(ManagedProperty.PropertyInfo<T> property, T value)
        {
            if (value is IEntityOrList)
                (value as IEntityOrList).SetParent(this);
            base.LoadProperty<T>(property, value);
        }

        #endregion
    }
}
